package com.tao.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.tao.constant.MessageConstant;
import com.tao.constant.StatusConstant;
import com.tao.context.UserContext;
import com.tao.mapper.ProductMapper;
import com.tao.pojo.dto.PageSelectProductDto;
import com.tao.pojo.dto.ProductDto;
import com.tao.pojo.entity.Product;
import com.tao.pojo.vo.ProductVo;
import com.tao.pojo.vo.SetmealProductVo;
import com.tao.result.PageResult;
import com.tao.service.ProductService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Set;

@Service
@Slf4j
public class ProductService1 implements ProductService {
    @Autowired
    ProductMapper productMapper;

    @Autowired
    RedisTemplate redisTemplate;
    @Override
    public void deleteProductService( List<Integer> idList) {
        //增删改时需要删除缓存数据，以免下次查询原先缓存的数据，丢失修改
        //只影响一个数据时，可以精确清理对应缓存；若影响多个数据时，为了方便，直接清理全部缓存
        //一次删除可以删除多个，为了方便，清理全部缓存

        //批量删除key时，需要传key的集合,获取key的集合需要进行匹配
        Set keys = redisTemplate.keys("product_*");
        redisTemplate.delete(keys);
        log.info("缓存清理成功");
        //cleanCache();
        //cleanCachePlus("product_*");

        for(Integer id : idList){
            if(productMapper.getByIdMapper(id).getStatus().equals(StatusConstant.ENABLE)){
                idList.remove(idList.indexOf(id));
                throw new RuntimeException(MessageConstant.DISH_ON_SALE);
            }
        }
        log.info("Service接收到的产品id：{}", idList);
        productMapper.deleteProductMapper(idList);


        //有待完善关联删除 -> 解决办法：起售与关联套餐时禁止删除 真关联的话太麻烦

    }

    @Override
    public List<Product> selectByCategoryIdService(Integer categoryId) {
        log.info("分类id:{}", categoryId);

        String key = "product_" + categoryId;//key的命名方式，固定识别码+唯一标识（一般为id）

        ListOperations listOperations = redisTemplate.opsForList();
        //redis工具类获取集合操作工具
        //一般返回结果是什么，redis就放什么

        //先查询redis看有没有缓存，怎么存的怎么接收
        List<Product> products;
        if(listOperations.size(key)>0){
            log.info("缓存中有该产品数据");
            products = listOperations.range(key,0,-1);
        }else
        {
            log.info("缓存中没有该产品数据");
            products = productMapper.selectByCategoryIdMapper(categoryId);
            //查询后需要放在redis中，这样下次可直接查看缓存

            listOperations.rightPushAll(key,products);
            //对于 Redis 来说，所有存储的数据都是字节序列，所以在存储复杂的对象（Product 对象）时，必须先将它们序列化
            //否则无法存储

            log.info("缓存中已添加该产品数据");
        }


        log.info("该分类产品：{}", products);
        return products;
    }

    @Override
    @Transactional
    public void addProductService(ProductDto productDto) {
        //增删改时需要删除缓存数据，以免下次查询原先缓存的数据，丢失修改
        //只影响一个数据时，可以精确清理对应缓存；若影响多个数据时，为了方便，直接清理全部缓存
        //add只影响一个，故可精确清理缓存
        String key = "product_" + productDto.getCategoryId();
        redisTemplate.delete(key);
        log.info("缓存清理成功");
        //cleanCachePlus(key);

        log.info("Controller传来的产品表单数据：{}", productDto);
        Product product = new Product();
        BeanUtils.copyProperties(productDto, product);
        product.setUpdateTime(LocalDateTime.now());
        product.setCreateTime(LocalDateTime.now());
        product.setCreateUser(UserContext.getThreadUserId());
        product.setUpdateUser(UserContext.getThreadUserId());
        productMapper.addProductMapper(product);
        log.info("成功添加产品：{}", product);

    }

    @Override
    @Cacheable(value = "products", key = "#pageSelectProductDto.page + '-' + #pageSelectProductDto.pageSize + '-' + #pageSelectProductDto.categoryId")
    public PageResult pageSelectProductService(PageSelectProductDto pageSelectProductDto) {
        log.info("缓存未命中,查询数据库.........");
        PageHelper.startPage(pageSelectProductDto.getPage(), pageSelectProductDto.getPageSize());
        Page<ProductVo> productPage = productMapper.pageSelectProductMapper(pageSelectProductDto);

        PageResult pageResult = new PageResult(productPage.getTotal(), productPage.getResult());
        return pageResult;
    }

    @Override
    public void updateProductService(ProductDto productDto) {
        //增删改时需要删除缓存数据，以免下次查询原先缓存的数据，丢失修改
        //只影响一个数据时，可以精确清理对应缓存；若影响多个数据时，为了方便，直接清理全部缓存
        //一次update虽然只影响一个数据，但是可能修改category_id，可能涉及两份数据，因此直接删除全部缓存即可
        Set keys = redisTemplate.keys("product_*");
        redisTemplate.delete(keys);
        //cleanCache();
        //cleanCachePlus("product_*");

        Product product = new Product();
        BeanUtils.copyProperties(productDto, product);
        log.info("新的产品数据为:{}", product);
        productMapper.updateProductMapper(product);
        log.info("修改产品成功");


    }

    @Override
    public ProductVo getByIdService(Integer id) {
        ProductVo productVo = productMapper.getByIdMapper(id);

        log.info("产品视图信息：{}", productVo);
        return productVo;
    }

    @Override
    public void updateStatusService(Integer status,Integer id) {
        //虽然起售停售也只影像一份数据，但无法获取分类id，一切从简，因此全部删除即可
        Set keys = redisTemplate.keys("product_*");
        redisTemplate.delete(keys);
        log.info("缓存清理成功");
        //cleanCache();
        //cleanCachePlus("product_*");
            productMapper.updateStatus(status,id);
    }

    @Override
    public List<SetmealProductVo> selectProduct(String name) {
        return productMapper.selectProduct(name);
    }



    //由于删除缓存经常用到，可在这里抽取出来构造成一个方法
    // 由于key的关系，每个模块都应该有一个单独的清理缓存函数，因此无法创造一个清理缓存的函数来清理任意模块的缓存

    public void cleanCache(){
        Set keys = redisTemplate.keys("product_*");
        redisTemplate.delete(keys);
        log.info("缓存清理成功");
    }

    //八嘎！！！遇见可变的东西，提取为变量即可
    //这样既可清理任意模块缓存，又可以清理一个缓存，也可以清理多个
    public void cleanCachePlus(String pattern){
        Set keys = redisTemplate.keys(pattern);
        redisTemplate.delete(keys);
        log.info("缓存清理成功");
    }
}
